package com.angle.im.server.config;


import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;

import java.time.Duration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author zhangwei
 * redis的相关配置
 */
@Configuration
@EnableCaching
@Slf4j
public class RedisConfig {

    private static final Map<String, Long> KEY_EXPIRE_MAP = new HashMap<>();

    /*
     * 为了避免配置key的过期时间对其他配置产生影响和耦合
     * 统一在这里进行key的过期时间配置
     */
    static {
        //时间要用秒*分*小时*天*月的形式来注入,增加可读性
        KEY_EXPIRE_MAP.put("token", 60 * 60 * 24 * 30L);
        KEY_EXPIRE_MAP.put("server", -1L);
    }

    /**
     * 管理缓存
     *
     * @param factory
     * @return
     */
    @Bean
    @SuppressWarnings("all")
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        // 生成一个默认配置，通过config对象即可对缓存进行自定义配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 设置缓存的默认过期时间，也是使用Duration设置 当前默认1天
        config = config.entryTtl(Duration.ofDays(1))
                // 不缓存空值
                .disableCachingNullValues();
        Map<String, Object> cacheConfig = getCacheConfig(config);
        // 使用自定义的缓存配置初始化一个cacheManager
        return RedisCacheManager.builder(factory)
                // 注意这两句的调用顺序，一定要先调用该方法设置初始化的缓存名，再初始化相关的配置
                .initialCacheNames((Set<String>) cacheConfig.get("cacheNames"))
                .withInitialCacheConfigurations((Map<String, RedisCacheConfiguration>) cacheConfig.get("configMap"))
                //未在cacheNames中指定的缓存空间,将按照默认配置执行,只对@cache接管的缓存生效,主动存取不受此配置影响
                .cacheDefaults(config)
                .build();
    }

    /**
     * 构建key和过期时间的配置
     *
     * @param config
     * @return
     */
    private Map<String, Object> getCacheConfig(RedisCacheConfiguration config) {
        Map<String, Object> result = new HashMap<>(2);
        // 设置一个初始化的缓存空间set集合
        // 这样可以自定义@CacheConfig(cacheNames = "user")的过期时间
        Set<String> cacheNames = new HashSet<>();
        // 对每个缓存空间应用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>(3);
        KEY_EXPIRE_MAP.forEach((key, value) -> {
            cacheNames.add(key);
            configMap.put(key, config.entryTtl(Duration.ofSeconds(value)));
        });
        result.put("cacheNames", cacheNames);
        result.put("configMap", configMap);
        return result;
    }

}
